//Pseudo True Dual port Multibank SPSRAM specially for ysyx project
//Priority arbite configuration (By default, Port B is High priority)
`include "PRV564Config.v"
`include "PRV564Define.v"
module pTDPRAM_ysyx
#
(
    parameter BANK_COEFF=3
)
(
    input [5:0]addr_A,
    input [BANK_COEFF-1:0]bank_A,
    input ce_A,
    input [15:0]wbsel_A,
    output opvalid_A,
    output [127:0]dato_A,
    input [127:0]dati_A,

    input [5:0]addr_B,
    input [BANK_COEFF-1:0]bank_B,
    input ce_B,
    input [15:0]wbsel_B,
    output opvalid_B,
    output [127:0]dato_B,
    input [127:0]dati_B,

    input clk,rst
);
    localparam BANK_NUM=(2**BANK_COEFF);
    reg PrevOp_A,PrevOp_B;
    reg ce_B_Prev;
    reg blocked;
    reg [BANK_COEFF-1:0]bank_A_Hold,bank_B_Hold;
    wire [127:0]RdPortBankDat[BANK_NUM-1:0];//For Non-blocked Operation
    wire [127:0]wmask_A,wmask_B;
    wire [BANK_NUM-1:0]BankSel_A,BankSel_B;
    wire access_block;
    wire Write_A,Write_B;
    assign Write_A=(wbsel_A!=0);
    assign Write_B=(wbsel_B!=0);
    assign access_block = (bank_A == bank_B) & (ce_A & ce_B)|
                        (bank_A == bank_B_Hold) & (ce_A & ce_B_Prev);
    assign wmask_A= ~{
                    {8{wbsel_A[15]}},
                    {8{wbsel_A[14]}},
                    {8{wbsel_A[13]}},
                    {8{wbsel_A[12]}},
                    {8{wbsel_A[11]}},
                    {8{wbsel_A[10]}},
                    {8{wbsel_A[9]}},
                    {8{wbsel_A[8]}},
                    {8{wbsel_A[7]}},
                    {8{wbsel_A[6]}},
                    {8{wbsel_A[5]}},
                    {8{wbsel_A[4]}},
                    {8{wbsel_A[3]}},
                    {8{wbsel_A[2]}},
                    {8{wbsel_A[1]}},
                    {8{wbsel_A[0]}}
                };
    assign wmask_B= ~{
                    {8{wbsel_B[15]}},
                    {8{wbsel_B[14]}},
                    {8{wbsel_B[13]}},
                    {8{wbsel_B[12]}},
                    {8{wbsel_B[11]}},
                    {8{wbsel_B[10]}},
                    {8{wbsel_B[9]}},
                    {8{wbsel_B[8]}},
                    {8{wbsel_B[7]}},
                    {8{wbsel_B[6]}},
                    {8{wbsel_B[5]}},
                    {8{wbsel_B[4]}},
                    {8{wbsel_B[3]}},
                    {8{wbsel_B[2]}},
                    {8{wbsel_B[1]}},
                    {8{wbsel_B[0]}}
                };
    assign dato_A=RdPortBankDat[bank_A_Hold];
    assign dato_B=RdPortBankDat[bank_B_Hold];
    assign opvalid_A = (Write_A | (!PrevOp_A)) & (!access_block);
    assign opvalid_B = (Write_B | (!PrevOp_B));
    genvar i;
    generate
    for(i=0;i<BANK_NUM;i=i+1)//Bank Select Signal Generation
    begin : BANKSEL_GEN
        assign BankSel_A[i]=(bank_A == i) & ce_A;
        assign BankSel_B[i]=(bank_B == i) & ce_B;
    end

    for(i=0;i<BANK_NUM;i=i+1)//Cache Ram Generation
    begin:CACHE_RAM_GEN
        S011HD1P_X32Y2D128_BW CACHEMEM
        (
            .Q(RdPortBankDat[i]), 
            .CLK(clk), 
            .CEN(1'b0),// ~(BankSel_A|BankSel_B)
            .WEN((BankSel_B[i] & ce_B)?(!Write_B): !(Write_A & BankSel_A[i])), 
            .BWEN((BankSel_B[i] & ce_B)?(wmask_B):(wmask_A | {128{!BankSel_A[i]}})),
            .A((BankSel_B[i] & ce_B)?addr_B:addr_A), 
            .D((BankSel_B[i] & ce_B)?dati_B:dati_A)
        );    
    end
    endgenerate
    //when blocked, set port A mode to Write,if port A next action is write, no more wait is need
    // when read, the latched Port B action needs 1 cycle to flush 
    always @(posedge clk) 
    begin
        PrevOp_A<=Write_A | access_block; 
        PrevOp_B<=Write_B;
        blocked<=access_block;
        bank_A_Hold<=bank_A;
        bank_B_Hold<=bank_B;
        ce_B_Prev<=ce_B;
    end



endmodule
